﻿using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using Microsoft.Extensions.DependencyInjection;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace UnitTests;

[TestClass]
public class 验证测试
{
    [TestMethod]
    public void Test()
    {
        var services = new ServiceCollection();
        services.AddTransient<MyClass>();
        services.AddSingleton(new MyService { Number = 1 });
        services.AddSingleton(new MyService2 { Number = -1 });
        services.AddSingleton(new MyService3 { Number = 2 });
        services.AddAutowired();
        var p = services.BuildServiceProvider();
        var my = p.GetRequiredService<MyClass>();
        Assert.IsNotNull(my.MyService);
        Assert.IsNotNull(my.MyService2);
        Assert.IsNotNull(my.MyService3);
    }
    [TestMethod]
    public void Test1()
    {
        var services = new ServiceCollection();
        services.AddTransient<MyClass>();
        services.AddSingleton(new MyService { Number = 0 });
        services.AddSingleton(new MyService2 { Number = -1 });
        services.AddSingleton(new MyService3 { Number = 2 });
        services.AddAutowired();
        var p = services.BuildServiceProvider();
        try
        {
            p.GetRequiredService<MyClass>();
            Assert.Fail();
        }
        catch (ValidationException e)
        {
            Assert.AreEqual("MyService validate fail", e.ValidationResult.ErrorMessage);
        }
    }

    [TestMethod]
    public void Test2()
    {
        var services = new ServiceCollection();
        services.AddTransient<MyClass>();
        services.AddSingleton(new MyService { Number = 1 });
        services.AddSingleton(new MyService2 { Number = 0 });
        services.AddSingleton(new MyService3 { Number = 2 });
        services.AddAutowired();
        var p = services.BuildServiceProvider();
        try
        {
            p.GetRequiredService<MyClass>();
            Assert.Fail();
        }
        catch (ValidationException e)
        {
            Assert.AreEqual("MyService2 validate fail", e.ValidationResult.ErrorMessage);
        }
    }


    [TestMethod]
    public void Test3()
    {
        var services = new ServiceCollection();
        services.AddTransient<MyClass>();
        services.AddSingleton(new MyService { Number = 1 });
        services.AddSingleton(new MyService2 { Number = -1 });
        services.AddAutowired();
        var p = services.BuildServiceProvider();
        try
        {
            var my = p.GetRequiredService<MyClass>();
            Assert.Fail();
        }
        catch (ValidationException e)
        {
            Assert.AreEqual("MyService3 is null", e.ValidationResult.ErrorMessage);
        }
    }

    [TestMethod]
    public void Test4()
    {
        var services = new ServiceCollection();
        services.AddTransient<MyClass>();
        services.AddSingleton(new MyService { Number = 1 });
        services.AddSingleton(new MyService2 { Number = -1 });
        services.AddSingleton(new MyService3 { Number = 3 });
        services.AddAutowired();
        var p = services.BuildServiceProvider();
        try
        {
            p.GetRequiredService<MyClass>();
            Assert.Fail();
        }
        catch (ValidationException e)
        {
            Assert.AreEqual("MyService3 validate fail", e.ValidationResult.ErrorMessage);
        }
    }

    class MyClass
    {
        [Autowired(Validate = true), Required]
        public MyService MyService { get; set; }
        [Autowired, Required, NumberValidation]
        public MyService2 MyService2 { get; set; }
        [Autowired(Validate = true), Required(ErrorMessage = "MyService3 is null")]
        public MyService3 MyService3 { get; set; }
    }


    class MyService : IValidatableObject
    {
        public int Number { get; set; }

        public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
        {
            if (Number <= 0)
            {
                yield return new ValidationResult("MyService validate fail", new[] { nameof(Number) });
            }
        }
    }

    class MyService2
    {
        public int Number { get; set; }

    }

    class NumberValidation : ValidationAttribute
    {
        protected override ValidationResult IsValid(object value, ValidationContext validationContext)
        {
            if (value is MyService2 service2 && service2.Number >= 0)
            {
                return new ValidationResult("MyService2 validate fail", ["Number"]);
            }
            return ValidationResult.Success!;
        }
    }

    class MyService3
    {
        [Range(1, 2, ErrorMessage = "MyService3 validate fail")]
        public int Number { get; set; }
    }

}
